package com.yunc.common.netty;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yunc.common.utils.SpringContextUtils;
import com.yunc.modules.chat.entity.ChatGroupsUser;
import com.yunc.modules.chat.service.IChatGroupsUserService;
import com.yunc.modules.cms.entity.CircleContent;
import com.yunc.modules.cms.service.ICircleContentService;
import com.yunc.modules.sys.entity.SysUser;
import com.yunc.modules.sys.entity.SysUserToken;
import com.yunc.modules.sys.service.ISysUserService;
import com.yunc.modules.sys.service.ISysUserTokenService;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * netty长连接handler实现
 *
 * @author taocongcong
 * @create 2019-03-12 14:47
 */
public class WebSocketServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private static final Logger logger = LogManager.getLogger(WebSocketServerHandler.class);

    private final static ISysUserTokenService sysUserTokenService = (ISysUserTokenService) SpringContextUtils.getBean("sysUserTokenService");
    private final static ICircleContentService circleContentService = (ICircleContentService) SpringContextUtils.getBean("circleContentService");
    private final static ISysUserService sysUserService = (ISysUserService) SpringContextUtils.getBean("sysUserService");
    private final static IChatGroupsUserService chatGroupsUserService = (IChatGroupsUserService) SpringContextUtils.getBean("chatGroupsUserService");

    /**
     * 不同组怎么处理
     */
    public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    /**
     * key是组名，value是组内成员
     */
    public static Map<String, ChannelGroup> channelGroupMap = new HashMap<>();

    /**
     * key用户id
     */
    public static Map<String, Channel> userChannelMap = new HashMap<>();

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        // System.out.println("收到消息: " + msg.text());
        JSONObject object = JSON.parseObject(msg.text());
        // 自定义协议。个人理解：协议就是个人定义数据格式，比如（1）聊天{userId:,content:}（2）智能聊天{message:}
        if (object.get(ChatStatusEnum.CIRCLE_CONTENT_ID.getValue()) != null) {
            String circleContentId = (String) object.get("circleContentId");
            long id = 0;
            if (StringUtils.isNotEmpty(circleContentId)) {
                id = Long.parseLong(circleContentId);
            }
            List<CircleContent> circleContentList = circleContentService.listSize(id, 5);
            String text = JSON.toJSONString(circleContentList);
            //读取收到的信息写回到客户端,ctx.channel是属于一个通道的
            ctx.channel().writeAndFlush(new TextWebSocketFrame(text));
        } else if (object.get(ChatStatusEnum.LOGIN.getValue()) != null) {
            String token = (String) object.get("login");
            SysUserToken sysUserToken = sysUserTokenService.getOne(new QueryWrapper<SysUserToken>().eq("token", token));
            if (sysUserToken != null) {
                userChannelMap.put(String.valueOf(sysUserToken.getUserId()), ctx.channel());
                // 查询出我所在的群，如果没有创建，如果有将其加入
                List<ChatGroupsUser> groupList = chatGroupsUserService.list(new QueryWrapper<ChatGroupsUser>().eq("user_id", sysUserToken.getUserId()));
                if (groupList != null && groupList.size() > 0) {
                    for (ChatGroupsUser group : groupList) {
                        Long groupId = group.getGroupId();
                        ChannelGroup channels = channelGroupMap.get(String.valueOf(groupId));
                        if (channels == null || channels.size() == 0) {
                            channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
                        }
                        channels.add(ctx.channel());
                        channelGroupMap.put(String.valueOf(groupId), channels);
                    }
                }
                // 修改在线状态
                SysUser record = new SysUser();
                record.setId(sysUserToken.getUserId());
                record.setLineStatus("2");
                sysUserService.updateById(record);
            }
        } else if (object.get(ChatStatusEnum.ADD_FRIEND.getValue()) != null) {
            // 加好友
            String toId = (String) object.get("toId");
            String token = (String) object.get("token");
            // 多线程保存数据进入message表
            // 获取channel
            SysUserToken sysUserToken = sysUserTokenService.getOne(new QueryWrapper<SysUserToken>().eq("token", token));
            Channel channel = userChannelMap.get(toId);
            if (channel != null) {
                // 定义好友返回格式
                String s = "{\"userid\":\"%s\",\"sendType\":\"%s\"}";
                String text = String.format(s, sysUserToken.getUserId(), 2);
                channel.writeAndFlush(new TextWebSocketFrame(text));
            }
            // 使用多线程保存信息
            // String postMessage = (String) object.get("postMessage");
            // AsyncManager.me().execute(AsyncFactory.insertFriendMessages(sysUserToken.getUserId(), toId, postMessage));
        } else if (object.get(ChatStatusEnum.AGREE_FRIEND.getValue()) != null) {
            // 同意加好友
            String toId = (String) object.get("toId");
            String toGroupId = (String) object.get("toGroupId");
            String fromId = (String) object.get("fromId");
            // 多线程保存数据进入message表
            // 获取channel
            SysUser sysUser = sysUserService.getById(Long.valueOf(fromId));
            Channel channel = userChannelMap.get(toId);
            if (channel != null) {
                // 定义好友返回格式
                String s = "{\"userName\":\"%s\",\"toGroupId\":\"%s\",\"headLogo\":\"%s\",\"id\":\"%s\",\"remark\":\"%s\",\"sendType\":\"%s\"}";
                String text = String.format(s, sysUser.getUserName(), toGroupId, sysUser.getHeadLogo(), sysUser.getId(), sysUser.getRemark(), 5);
                channel.writeAndFlush(new TextWebSocketFrame(text));
            }
        } else if (object.get(ChatStatusEnum.REFUSE_FRIEND.getValue()) != null) {
            // 拒绝加好友
            String toId = (String) object.get("toId");
            Channel channel = userChannelMap.get(toId);
            if (channel != null) {
                // 定义好友返回格式
                String s = "{\"sendType\":\"%s\"}";
                String text = String.format(s, 6);
                channel.writeAndFlush(new TextWebSocketFrame(text));
            }
        } else if (object.get(ChatStatusEnum.FRIEND_SEND_MESSAGE.getValue()) != null) {
            // 朋友间发信息
            String toId = (String) object.get("toId");
            String fromId = (String) object.get("fromId");
            String friendSendMessage = (String) object.get("friendSendMessage");
            // 获取channel
            SysUser sysUser = sysUserService.getById(Long.valueOf(fromId));
            Channel channel = userChannelMap.get(toId);
            if (channel != null) {
                // 定义好友返回格式
                String s = "{\"username\":\"%s\",\"avatar\":\"%s\",\"id\":\"%s\",\"type\":\"%s\",\"content\":\"%s\",\"sendType\":\"%s\"}";
                String text = String.format(s, sysUser.getUserName(), sysUser.getHeadLogo(), sysUser.getId(), "friend", friendSendMessage, "3");
                channel.writeAndFlush(new TextWebSocketFrame(text));
            }
            // 存进用户记录表中
        } else if (object.get(ChatStatusEnum.GROUP_SEND_MESSAGE.getValue()) != null) {
            String groupId = (String) object.get("groupId");
            String fromId = (String) object.get("fromId");
            String groupSendMessage = (String) object.get("groupSendMessage");
            // 获取channel
            SysUser sysUser = sysUserService.getById(Long.valueOf(fromId));

            ChannelGroup channels = channelGroupMap.get(groupId);
            if (channels != null && channels.size() > 0) {
                for (Channel channel : channels) {
                    if (channel != ctx.channel()) {
                        String s = "{\"username\":\"%s\",\"avatar\":\"%s\",\"id\":\"%s\",\"type\":\"%s\",\"content\":\"%s\",\"sendType\":\"%s\"}";
                        String text = String.format(s, sysUser.getUserName(), sysUser.getHeadLogo(), groupId, "group", groupSendMessage, "4");
                        channel.writeAndFlush(new TextWebSocketFrame(text));
                    }
                }
            }
            // 存进群组记录表中
        }
    }

    /**
     * 连接建立时
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        System.out.println("handlerAddred " + ctx.channel().id().asLongText());
        // 获取连接的channel
        Channel incomming = ctx.channel();
        // 通知所有已经连接到服务器的客户端，有一个新的通道加入
        /*for (Channel channel : channels) {
            System.out.print("[SERVER]-"+incomming.remoteAddress()+"加入\n");
        }*/
        logger.info("[SERVER]-"+incomming.remoteAddress()+"加入\n");
        channels.add(ctx.channel());

        //userChannelMap.put(String.valueOf(userId), incomming);
    }

    /**
     * 连接关闭时
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        System.out.println("handlerRemoved " + ctx.channel().id().asLongText());
        //获取连接的channel
        Channel incomming = ctx.channel();
        /*for (Channel channel : channels) {
            channel.writeAndFlush("[SERVER]-"+incomming.remoteAddress()+"离开\n");
        }*/
        logger.info("[SERVER]-"+incomming.remoteAddress()+"离开\n");
        //从服务端的channelGroup中移除当前离开的客户端
        channels.remove(ctx.channel());
        //userChannelMap.remove(String.valueOf(userId));
        // 关闭其他
        String userId = "";
        if (userChannelMap != null && userChannelMap.size() > 0) {
            Iterator<Map.Entry<String, Channel>> it = userChannelMap.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, Channel> entry = it.next();
                if (entry.getValue() == ctx.channel()) {
                    // 删除元素
                    it.remove();
                    userId = entry.getKey();
                }
            }
        }
        if (channelGroupMap != null && channelGroupMap.size() > 0) {
            for (Map.Entry<String, ChannelGroup> entry : channelGroupMap.entrySet()) {
                ChannelGroup value = entry.getValue();
                value.remove(ctx.channel());
            }
        }
        // 获取userId,修改其在线状态
        if (StringUtils.isNotEmpty(userId)) {
            SysUser record = new SysUser();
            record.setId(Long.valueOf(userId));
            record.setLineStatus("1");
            sysUserService.updateById(record);
        }
    }

    /**
     * 异常发生时
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("异常发生");
        ctx.close();
    }
}
